package com.aboverock.module.system.web;

import com.aboverock.common.domain.Result;
import com.aboverock.common.enums.LimitOperationEnum;
import com.aboverock.common.enums.MessageSourceKey;
import com.aboverock.core.spring.web.StringIdBaseController;
import com.aboverock.module.system.domain.Dictionary;
import com.aboverock.module.system.i18n.KbSmartMessageSourceKey;
import com.aboverock.module.system.service.DictionaryService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 前端控制器.
 * </p>
 *
 * @author Rock Wang.yuan
 * @since 2018-08-09
 */
@RestController
@RequestMapping("system/dictionary")
@Validated
public class DictionaryController extends StringIdBaseController<Dictionary> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private DictionaryService dictionaryService;

    private final ReentrantLock operationLock = new ReentrantLock();

    @ApiOperation(value = "获取所有字典数据")
    @Override
    @Deprecated
    public Result all(HttpServletRequest request) {
        List<Dictionary> list = dictionaryService
                .list(new QueryWrapper<Dictionary>().orderByAsc("order_no"));
        return Result.success(list);
    }

    @ApiOperation(value = "获取所有字典数据，并封装成树结构")
    @GetMapping("tree/all")
    public Result allDictionariesTree() {
        List<Dictionary> dictionaries = dictionaryService.list(null);
        
        Map<String, List<Dictionary>> typeMap = new HashMap<>(16);
        dictionaries.forEach(dictionary -> {
            String typeCode = dictionaryService.getDictionaryTypeCode(dictionary);
            if (null == typeMap.get(typeCode)) {
                typeMap.put(typeCode, new ArrayList<Dictionary>());
            }
            typeMap.get(typeCode).add(dictionary);
        });

        List<Dictionary> result = typeMap.values().stream()
                .map(list -> dictionaryService.buildTree(list))
                .sorted(Comparator.comparing(Dictionary::getOrderNo))
                .collect(Collectors.toList());
        return Result.success(result);
    }

    @ApiOperation(value = "保存字典数据")
    @Override
    public Result save(@Validated @RequestBody Dictionary dictionary) {
        operationLock.lock();
        try {
            // parent id不为空，则对应的父字典必须存在
            if (dictionary.getParentId() != null
                    && null == dictionaryService.getById(dictionary.getParentId())) {
                return Result.fail(KbSmartMessageSourceKey.PARENT_NODE_NOT_FOUND);
            }

            if (dictionaryService.isDuplicatedCode(dictionary)) {
                return Result.fail(MessageSourceKey.Common.COMMON_CODE_EXISTED);
            }

            dictionary.setOrderNo(System.currentTimeMillis());
            return super.save(dictionary);
        } finally {
            operationLock.unlock();
        }
    }

    @ApiOperation(value = "更新字典数据")
    @Override
    public Result update(@PathVariable("id") String id,
            @Validated @RequestBody Dictionary dictionary) {
        operationLock.lock();
        try {
            Dictionary dic = dictionaryService.getById(id);
            if (null == dic) {
                return Result.fail(MessageSourceKey.Common.COMMON_DATA_NOT_FOUND_KEY);
            }

            // 以path中id为准
            dictionary.setId(id);
            // 更新了code
            if (!dictionary.getCode().equalsIgnoreCase(dic.getCode())) {
                if (LimitOperationEnum.UPDATE_CODE_AND_DELETE_REFUSED.getValue()
                        .equals(dic.getLimitOperation())) {
                    return Result.fail(MessageSourceKey.Common.COMMON_CODE_FIXED);
                }

                if (dictionaryService.isDuplicatedCode(dictionary)) {
                    return Result.fail(MessageSourceKey.Common.COMMON_CODE_EXISTED);
                }
            }

            try {
                dictionaryService.update(dictionary, dic);
                return Result.success(dictionary);
            } catch (SQLException e) {
                logger.warn("Data-Smart:更新字典数据失败", e);
            }
            return Result.fail();
        } finally {
            operationLock.unlock();
        }
    }

    @ApiOperation(value = "删除字典数据")
    @Override
    public Result delete(@PathVariable("id") String id) {
        operationLock.lock();
        try {
            Dictionary dictionary = dictionaryService.getById(id);
            if (null == dictionary) {
                return Result.success();
            }

            if (LimitOperationEnum.DELETE_REFUSED.getValue().equals(dictionary.getLimitOperation())
                    || LimitOperationEnum.UPDATE_CODE_AND_DELETE_REFUSED.getValue()
                            .equals(dictionary.getLimitOperation())) {
                return Result.fail(MessageSourceKey.Common.COMMON_DATA_DELETE_REFUSE_KEY);
            }
            if (dictionaryService.remove(dictionary)) {
                return Result.success();
            }
            return Result.fail();
        } finally {
            operationLock.unlock();
        }
    }

    /**
     * 交换两个字典/字典类型的顺序.
     *
     * @param dictionaryIds the dictionary ids
     * @return the result
     */
    @ApiOperation(value = "交换两个字典/字典类型的顺序")
    @PatchMapping("order/action/exchange")
    public Result exchangeOrderNo(@RequestBody @Size(min = 2, max = 2) List<Long> dictionaryIds) {
        operationLock.lock();
        try {
            List<Dictionary> dictionaries = dictionaryService
                    .list(new QueryWrapper<Dictionary>().in("id", dictionaryIds));
            if (dictionaries.size() != 2) {
                return Result.fail(MessageSourceKey.Common.COMMON_DATA_NOT_FOUND_KEY);
            }

            try{
                dictionaryService.exchangeOrderNo(dictionaries.get(0), dictionaries.get(1));
                return Result.success();
            } catch (SQLException e) {
                logger.warn("Data-Smart:字典数据顺序交换失败", e);
            }
            return Result.fail();
        } finally {
            operationLock.unlock();
        }
    }

    @ApiOperation(value = "根据code获取字典类型，若没有传入code，则返回所有字典类型")
    @GetMapping("/type")
    public Result getDictionaryType(@RequestParam(required = false) String typeCode) {
        if (StringUtils.isBlank(typeCode)) {
            return Result.success(dictionaryService.getAllDictionaryType());
        }

        List<Dictionary> list = new ArrayList<>();
        Dictionary dictionary = dictionaryService.getDictionaryTypeByCode(typeCode);
        if (dictionary != null) {
            list.add(dictionary);
        }
        return Result.success(list);
    }

    @ApiOperation(value = "根据字典各层级code获取对应字典及其所有子级数据字典")
    @ApiImplicitParam(name = "codes", value = "数组：各层级字典code")
    @GetMapping("tree")
    public Result getDictionaryTreeByCodes(@RequestParam String[] codes) {
        return Result.success(dictionaryService.getDictionaryTreeByCodes(codes));
    }
    
    @ApiOperation(value = "根据字典类型code或者parentId获取其子一级数据字典")
    @ApiImplicitParams({ @ApiImplicitParam(name = "typeCode", value = "字典类型code", required = false),
        @ApiImplicitParam(name = "parentId", value = "parent id", required = false) })
    @GetMapping("children")
    @Deprecated
    public Result getSublevelDictionaries(@RequestParam(required = false) String typeCode,
            @RequestParam(required = false) String parentId) {
        if (!StringUtils.isBlank(typeCode)) {
            return Result.success(dictionaryService.getDictionariesByTypeCode(typeCode));
        }
        if (!StringUtils.isBlank(parentId)) {
            return Result.success(dictionaryService.getDictionariesByParentId(parentId));
        }

        return Result.fail(MessageSourceKey.Common.COMMON_PARAM_IS_INVALID_KEY);
    }

    @ApiOperation(value = "根据字典类型code获取其所有子级数据字典")
    @ApiImplicitParam(name = "typeCode", value = "字典类型code", required = true)
    @GetMapping("children/all")
    @Deprecated
    public Result getAllDictionariesByTypeCode(@RequestParam String typeCode) {
        if (StringUtils.isBlank(typeCode)) {
            return Result.fail(MessageSourceKey.Common.COMMON_PARAM_IS_INVALID_KEY);
        }

        return Result.success(dictionaryService.getAllDictionariesByTypeCode(typeCode));
    }

    @Override
    @ApiOperation(value = "禁用该通用接口")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result page(HttpServletRequest request) {
        return null;
    }
}
